﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Dynamic.Core;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using PMS.SANY.Entity;
using PMS.SANY.IBusiness;
using PMS.SANY.Util;
using PMS.SANY.Models;

namespace PMS.SANY.Business
{
    public class Sys_RoleBusiness : BusRepository<Sys_Role>, ISys_RoleBusiness, IScopedDependency
    {
        private IServiceProvider SvcProvider { get; set; }
        public Sys_RoleBusiness(GDbContext context, IServiceProvider svcProvider)
            : base(context)
        {
            this.SvcProvider = svcProvider;
        }

        public Task<PageResult<Sys_Role>> GetPageResultAsync(PageInput<Sys_RoleQM> query)
        {
            var queryable = this.GetQueryable(true);
            var search = query.Search;
            if (!search.Name.IsNullOrEmpty())
                queryable = queryable.Where(w => w.Name.Contains(search.Name));

            return this.GetPageResultAsync(queryable, query);
        }

        public async Task<List<TreeModel>> GetMenuAsync()
        {
            var menus = await this.GetQueryable<Sys_Menu>(true).ToListAsync();

            var treeMenu = menus.Select(s => new TreeModel()
            {
                Id = s.Id,
                Value = "Menu",
                ParentId = s.ParentId,
                Text = $"{s.Name}({s.Code})"
            }).ToList();

            var actions = await this.GetQueryable<Sys_Action>(true).ToListAsync();

            var treeAction = actions.Select(s => new TreeModel()
            {
                Id = s.Id,
                Value = "Action",
                ParentId = s.MenuId,
                Text = $"{s.Name}({s.Code})"
            }).ToList();

            var tree = new List<TreeModel>();
            tree.AddRange(treeMenu);
            tree.AddRange(treeAction);
            var result = TreeHelper.BuildTree(tree);
            return result;
        }

        public async Task<List<string>> GetAccessAsync(string roleId)
        {
            var menuIds = await this.GetQueryable<Sys_RoleMenu>(true).Where(w => w.RoleId == roleId).Select(s => s.MenuId).ToListAsync();
            var actionIds = await this.GetQueryable<Sys_RoleAction>(true).Where(w => w.RoleId == roleId).Select(s => s.ActionId).ToListAsync();
            var ids = new List<string>();
            ids.AddRange(menuIds);
            ids.AddRange(actionIds);

            return ids;
        }

        public async Task<int> SaveAccessAsync(string roleId, List<KeyValuePair<string, string>> access)
        {
            var menuIds = access.Where(w => w.Value == "Menu").Select(s => s.Key).ToList();
            var actionIds = access.Where(w => w.Value == "Action").Select(s => s.Key).ToList();

            var menuSvc = this.SvcProvider.GetRequiredService<ISys_RoleMenuBusiness>();
            var dbMenus = await menuSvc.GetListAsync(w => w.RoleId == roleId);
            var delMenus = dbMenus.Where(w => !menuIds.Contains(w.MenuId)).ToList();
            if (delMenus.Count > 0)
                await menuSvc.DeleteAsync(delMenus);
            var newMenus = menuIds.Except(dbMenus.Select(s => s.MenuId)).Select(s => new Sys_RoleMenu() { RoleId = roleId, MenuId = s }).ToList();
            if (newMenus.Count > 0)
                await menuSvc.AddAsync(newMenus);

            var actionSvc = this.SvcProvider.GetRequiredService<ISys_RoleActionBusiness>();
            var dbActions = await actionSvc.GetListAsync(w => w.RoleId == roleId);
            var delActions = dbActions.Where(w => !actionIds.Contains(w.ActionId)).ToList();
            if (delActions.Count > 0)
                await actionSvc.DeleteAsync(delActions);
            var newActions = actionIds.Except(dbActions.Select(s => s.ActionId)).Select(s => new Sys_RoleAction() { RoleId = roleId, ActionId = s }).ToList();
            if (newActions.Count > 0)
                await actionSvc.AddAsync(newActions);
            return access.Count;
        }
    }
}
